package com.ht.modules.alarmstatis.service.impl;

import com.ht.modules.alarmstatis.entity.*;
import com.ht.modules.alarmstatis.mapper.AlarmStatisMapper;
import com.ht.modules.alarmstatis.service.IAlarmStatisService;
import com.ht.modules.device.entity.DateUtils;
import com.ht.modules.utils.DicConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 *  报警统计
 * @Author:
 * @Date: 2024-01-11
 * @Version: V1.0
 */
@Slf4j
@Service
public class AlarmStatisServiceImpl implements IAlarmStatisService {
    private static final String YEAR_PATTERN = "yyyy-01-01 00:00:00";
    private static final String MONTH_PATTERN = "yyyy-MM-01 00:00:00";
    private static final String WEEK_PATTERN = "yyyy-MM-dd 00:00:00";
    private static final String DAY_PATTERN = "yyyy-MM-dd 00:00:00";
    private static final String CURRENT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    @Autowired
    private AlarmStatisMapper alarmStatisMapper;

    /**
     * 报警总表
     *
     * @param alarmMaster 参数
     */
    @Override
    public List<AlarmMasterVo> alarmMasterList(AlarmMaster alarmMaster) {
        if (alarmMaster == null) {
            alarmMaster = new AlarmMaster();
        }
        Date startTime = alarmMaster.getStartTime();
        Date endTime = alarmMaster.getEndTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        if (null != startTime && null != endTime) {
            BigDecimal toSecond = new BigDecimal(1000 * 60 * 60 * 24);
            BigDecimal startTimeMs = new BigDecimal(startTime.getTime());
            BigDecimal endTimeMs = new BigDecimal(endTime.getTime());
            BigDecimal days = (endTimeMs.subtract(startTimeMs)).divide(toSecond, 0, RoundingMode.HALF_UP);
            if (days.compareTo(BigDecimal.ONE) >= 0) {
                alarmMaster.setIntervalDay(String.valueOf(days));
                cal.setTime(startTime);
                cal.add(Calendar.DATE, -days.intValue());
                alarmMaster.setLastStartTime(sdf.format(cal.getTime()));
                cal.setTime(endTime);
                cal.add(Calendar.DATE, -days.intValue());
                alarmMaster.setLastEndTime(sdf.format(cal.getTime()));
            } else {
                BigDecimal seconds = (endTimeMs.subtract(startTimeMs)).divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP);
                alarmMaster.setIntervalDay("0");
                cal.setTime(startTime);
                cal.add(Calendar.SECOND, -seconds.intValue());
                alarmMaster.setLastStartTime(sdf.format(cal.getTime()));
                cal.setTime(endTime);
                cal.add(Calendar.SECOND, -seconds.intValue());
                alarmMaster.setLastEndTime(sdf.format(cal.getTime()));
            }
        } else {
            throw new RuntimeException("缺少查询时间段！");
        }
        List<AlarmMaster> alarmMasterVos = alarmStatisMapper.alarmMasterList(alarmMaster);
        AlarmMaster alarmMasterVo = new AlarmMaster();
        alarmMasterVo.setCentreName("全厂汇总");
        alarmMasterVo.setIntervalDay(alarmMaster.getIntervalDay());
        alarmMasterVo.setDeviceName(alarmMasterVos.size() + "个装置");
        int allCount = alarmMasterVos.stream().map(AlarmMaster::getAlarmCount).reduce(0, Integer::sum);
        Integer lastAllCount = alarmMasterVos.stream().map(AlarmMaster::getLastAlarmCount).reduce(0, Integer::sum);
        Integer disposeCount = alarmMasterVos.stream().map(AlarmMaster::getDisposeCount).reduce(0, Integer::sum);
        Integer chainCount = alarmMasterVos.stream().map(AlarmMaster::getChainCount).reduce(0, Integer::sum);
        alarmMasterVo.setAlarmCount(allCount);
        alarmMasterVo.setLastAlarmCount(lastAllCount);
        alarmMasterVo.setDisposeCount(disposeCount);
        alarmMasterVo.setChainCount(chainCount);
        BigDecimal disposeRate = allCount == 0 ? BigDecimal.ZERO : new BigDecimal(disposeCount).multiply(new BigDecimal(100)).divide(new BigDecimal(allCount), 2, RoundingMode.HALF_UP);
        alarmMasterVo.setDisposeRate(disposeRate + "%");
        BigDecimal alarmCount = new BigDecimal(alarmMasterVo.getAlarmCount().toString());
        BigDecimal lastAlarmCount = new BigDecimal(alarmMasterVo.getLastAlarmCount().toString());
        BigDecimal intervalDay = new BigDecimal(alarmMasterVo.getIntervalDay());
        intervalDay = intervalDay.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ONE : intervalDay;
        alarmMasterVo.setDayAlarmAvg(new BigDecimal(allCount).divide(intervalDay, 2, RoundingMode.HALF_UP));
        int flag = alarmCount.subtract(lastAlarmCount).compareTo(BigDecimal.ZERO);
        alarmMasterVo.setColor(flag < 0 ? "green" : flag == 0 ? "" : "red");
        String prefix = flag < 0 ? "" : flag == 0 ? "" : "+";
        BigDecimal chainRatio = alarmCount.subtract(lastAlarmCount).multiply(BigDecimal.valueOf(100)).divide((lastAlarmCount.compareTo(BigDecimal.ZERO) == 0 ? new BigDecimal("1") : lastAlarmCount), 2, RoundingMode.HALF_UP);
        alarmMasterVo.setChainRatio((flag > 0 ? "+" : "") + (alarmCount.subtract(lastAlarmCount)) + "（" + prefix + chainRatio + "%）");
        alarmMasterVos.add(alarmMasterVo);
        List<AlarmMasterVo> data = new ArrayList<>();
        LinkedHashMap<String, List<AlarmMaster>> map = alarmMasterVos.stream().collect(Collectors.groupingBy(AlarmMaster::getCentreName, LinkedHashMap::new, Collectors.toList()));
        for (String key : map.keySet()) {
            int departCount = 0;
            List<AlarmMaster> value = map.get(key);
            if (null != value) {
                departCount = value.stream().map(AlarmMaster::getAlarmCount).reduce(0, Integer::sum);
            }
            AlarmMasterVo alarmMasterV = new AlarmMasterVo();
            alarmMasterV.setData(value);
            alarmMasterV.setCentreName(key);
            alarmMasterV.setCentreCount(departCount);
            data.add(alarmMasterV);
        }
        return data;
    }


    /**
     * 报警频次统计
     *
     * @param alarmEqu 参数
     */
    @Override
    public List<AlarmEqu> alarmEquList(AlarmEqu alarmEqu) {
        List<AlarmEqu> alarmEqus = alarmStatisMapper.alarmEquList(alarmEqu);
        BigDecimal oneHundred = new BigDecimal(100);
        for (AlarmEqu eMap : alarmEqus) {
            BigDecimal pointCentreRate = new BigDecimal(eMap.getPointCount()).multiply(oneHundred)
                    .divide(new BigDecimal(eMap.getCentreCount()), 2, RoundingMode.HALF_UP);
            eMap.setPointCentreRate(pointCentreRate);
            BigDecimal pointDeviceRate = new BigDecimal(eMap.getPointCount()).multiply(oneHundred)
                    .divide(new BigDecimal(eMap.getDeviceCount()), 2, RoundingMode.HALF_UP);
            eMap.setPointDeviceRate(pointDeviceRate);
            BigDecimal pointUnitRate = new BigDecimal(eMap.getPointCount()).multiply(oneHundred)
                    .divide(new BigDecimal(eMap.getUnitCount()), 2, RoundingMode.HALF_UP);
            eMap.setPointUnitRate(pointUnitRate);
        }
        return alarmEqus;
    }

    /**
     * 报警类型统计
     *
     * @param alarmFromStatis 参数
     */
    @Override
    public List<AlarmFromStatis> alarmFromList(AlarmFromStatis alarmFromStatis) {
        List<AlarmFromStatis> alarmFromStatisList = alarmStatisMapper.alarmFromList(alarmFromStatis);
        BigDecimal oneHundred = new BigDecimal(100);
        for (AlarmFromStatis eMap : alarmFromStatisList) {
            BigDecimal percent = eMap.getDisposeCount().multiply(oneHundred)
                    .divide(eMap.getAlarmCount(), 2, RoundingMode.HALF_UP);
            eMap.setPercent(percent);
        }
        return alarmFromStatisList;
    }

    /**
     * 报警类型统计（分中心）
     *
     * @param alarmFromCentreStatis 参数
     */
    @Override
    public List<AlarmFromCentreStatis> alarmFromCentreList(AlarmFromCentreStatis alarmFromCentreStatis) {
        List<AlarmFromCentreStatis> alarmFromCentreList = alarmStatisMapper.alarmFromCentreList(alarmFromCentreStatis);
        BigDecimal oneHundred = new BigDecimal(100);
        for (AlarmFromCentreStatis eMap : alarmFromCentreList) {
            BigDecimal percent = eMap.getDisposeCount().multiply(oneHundred)
                    .divide(eMap.getAlarmCount(), 2, RoundingMode.HALF_UP);
            eMap.setPercent(percent);
        }
        return alarmFromCentreList;
    }

    /**
     * 报警优先级统计（不分页）
     *
     * @param alarmPriority 参数
     */
    @Override
    public List<AlarmPriority> alarmPriority(AlarmPriority alarmPriority) {
        if (null == alarmPriority.getIsTop()) {
            alarmPriority.setIsTop(false);
        }
        List<AlarmPriority> alarmPriorities = alarmStatisMapper.alarmPriority(alarmPriority);
        if (alarmPriorities.isEmpty()) {
            return new ArrayList<>();
        }
        int allCount = alarmPriorities.stream().map(AlarmPriority::getAlarmCount).reduce(0, Integer::sum);
        if (allCount == 0) {
            return alarmPriorities;
        }
        for (AlarmPriority item : alarmPriorities) {
            BigDecimal percent = BigDecimal.valueOf(item.getAlarmCount()).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(allCount), 2, RoundingMode.HALF_UP);
            item.setPercent(percent);
        }
        return alarmPriorities;
    }

    /**
     * 年月周分析（不分页）
     *
     * @param alarmYearMonthWeekAnalysis 参数
     */
    @Override
    public List<AlarmYearMonthWeekAnalysis> alarmYearMonthWeekAnalysis(AlarmYearMonthWeekAnalysis alarmYearMonthWeekAnalysis) {
        try {
            List<AlarmYearMonthWeekAnalysis> data = new ArrayList<>();
            List<AlarmYearMonthWeekAnalysis> alarmYearMonthWeekAnalyses = alarmStatisMapper.alarmYearMonthWeekAnalysis(alarmYearMonthWeekAnalysis);
            if (alarmYearMonthWeekAnalyses.isEmpty()) {
                return data;
            }
            int allCount = alarmYearMonthWeekAnalyses.size();
            String alarmAnalysisCycle = alarmYearMonthWeekAnalysis.getAlarmAnalysisCycle();
            if (Strings.isBlank(alarmAnalysisCycle)) {
                alarmAnalysisCycle = DicConstants.ALARM_ANALYSIS_CYCLE_MONTH;
            }
            Calendar calendar = Calendar.getInstance();
            Date startTime = alarmYearMonthWeekAnalysis.getStartTime();
            Date endTime = alarmYearMonthWeekAnalysis.getEndTime();
            if (endTime == null) {
                endTime = DateUtils.parseDate(DateUtils.formatDate(new Date(), CURRENT_PATTERN), CURRENT_PATTERN);
            }
            if (startTime == null) {
                switch (alarmAnalysisCycle) {
                    case DicConstants.ALARM_ANALYSIS_CYCLE_YEAR:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(endTime, YEAR_PATTERN), DAY_PATTERN));
                        calendar.add(Calendar.YEAR, -1);
                        break;
                    case DicConstants.ALARM_ANALYSIS_CYCLE_MONTH:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(endTime, MONTH_PATTERN), DAY_PATTERN));
                        calendar.add(Calendar.MONTH, -1);
                        break;
                    case DicConstants.ALARM_ANALYSIS_CYCLE_WEEK:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(endTime, WEEK_PATTERN), DAY_PATTERN));
                        calendar.add(Calendar.WEEK_OF_MONTH, -1);
                        break;
                    default:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(endTime, DAY_PATTERN), DAY_PATTERN));
                        calendar.add(Calendar.DATE, -1);
                        break;
                }
                startTime = calendar.getTime();
            }
            if (endTime.compareTo(startTime) == 0) {
                AlarmYearMonthWeekAnalysis item = new AlarmYearMonthWeekAnalysis();
                item.setStartTime(startTime);
                item.setEndTime(endTime);
                item.setAlarmCount(alarmYearMonthWeekAnalyses.size());
                BigDecimal percent = BigDecimal.valueOf(alarmYearMonthWeekAnalyses.size()).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(allCount), 2, RoundingMode.HALF_UP);
                item.setPercent(percent);
                data.add(item);
                return data;
            }
            while (endTime.compareTo(startTime) >= 0) {
                switch (alarmAnalysisCycle) {
                    case DicConstants.ALARM_ANALYSIS_CYCLE_YEAR:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(startTime, YEAR_PATTERN), YEAR_PATTERN));
                        calendar.add(Calendar.YEAR, 1);
                        break;
                    case DicConstants.ALARM_ANALYSIS_CYCLE_MONTH:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(startTime, MONTH_PATTERN), MONTH_PATTERN));
                        calendar.add(Calendar.MONTH, 1);
                        break;
                    case DicConstants.ALARM_ANALYSIS_CYCLE_WEEK:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(startTime, WEEK_PATTERN), WEEK_PATTERN));
                        calendar.add(Calendar.WEEK_OF_MONTH, 1);
                        break;
                    default:
                        calendar.setTime(DateUtils.parseDate(DateUtils.formatDate(startTime, DAY_PATTERN), DAY_PATTERN));
                        calendar.add(Calendar.DATE, 1);
                        break;
                }
                Date midTime = calendar.getTime();
//                midTime = midTime.compareTo(endTime) >= 0 ? endTime : midTime;
                Date finalStartTime = startTime;
                long count = alarmYearMonthWeekAnalyses.stream().filter(item -> {
                    Date alarmTime = item.getAlarmTime();
                    return alarmTime.compareTo(finalStartTime) >= 0 && alarmTime.compareTo(midTime) <= 0;
                }).count();
                AlarmYearMonthWeekAnalysis item = new AlarmYearMonthWeekAnalysis();
                item.setStartTime(startTime);
                startTime = midTime;
                item.setEndTime(midTime);
                item.setAlarmCount(Integer.parseInt(String.valueOf(count)));
                BigDecimal percent = BigDecimal.valueOf(Long.parseLong(String.valueOf(count))).multiply(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(allCount), 2, RoundingMode.HALF_UP);
                item.setPercent(percent);
                data.add(item);
                if (midTime.compareTo(endTime) > 0) {
                    break;
                }
            }
            return data;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 报警分析－报警处置率
     *
     * @param alarmDisposeRate 参数
     */
    @Override
    public List<AlarmDisposeRate> alarmDisposeRate(AlarmDisposeRate alarmDisposeRate) {
        if (null == alarmDisposeRate.getIsTop()) {
            alarmDisposeRate.setIsTop(false);
        }
        List<AlarmDisposeRate> alarmConfirmationRateList = alarmStatisMapper.alarmDisposeRate(alarmDisposeRate);
        // 计算确认率
        BigDecimal oneHundred = new BigDecimal(100);
        for (AlarmDisposeRate eMap : alarmConfirmationRateList) {
            if (eMap.getAlarmCount().compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal affirmPercent = eMap.getDisposeCount().multiply(oneHundred).divide(eMap.getAlarmCount(), 2, RoundingMode.HALF_UP);
                eMap.setDisposePercent(affirmPercent);
            } else {
                eMap.setDisposePercent(BigDecimal.ZERO);
            }
        }
        return alarmConfirmationRateList;
    }

    @Override
    public List<AlarmTeamStatis> alarmKpiStatisTeam(AlarmTeamStatis alarmTeamStatis) {
        return alarmStatisMapper.alarmKpiStatisTeam(alarmTeamStatis);
    }

    @Override
    public List<AlarmCentreStatis> alarmKpiStatisCentre(AlarmCentreStatis alarmCentreStatis) {
        return alarmStatisMapper.alarmKpiStatisCentre(alarmCentreStatis);
    }

    @Override
    public List<AlarmCrossTeamStatis> alarmKpiStatisCrossTeam(AlarmCrossTeamStatis alarmCrossTeamStatis) {
        return alarmStatisMapper.alarmKpiStatisCrossTeam(alarmCrossTeamStatis);
    }

}
